package poker.ai;

import java.util.ArrayList;

import enums.ActionEnum;
import enums.ActionType;
import enums.PlayersLeft;
import enums.TablePosition;

import poker.GameRound;
import poker.HandStrength;
import poker.Player;
import poker.Printer;
import poker.Rules;

public class SmartAI extends Player
{
	OpponentModeler opponentModeler;
	
	double handStrengthPreFlop;
	double handStrength;
	boolean conservative; 
	
	public SmartAI(int startCash, String name, boolean conservative) 
	{
		super(startCash, name);
		this.conservative = conservative;
	}

	@Override
	public ActionType chooseAction(GameRound gameRound) 
	{
		opponentModeler = OpponentModeler.getInstance();

		double bestPredictedHandStrength = 0;
		if(gameRound.getRounds() > 500)
		{
			for (int i = 0; i < gameRound.getPlayers().size(); i++) {
				Player player = gameRound.getPlayers().get(i);
				
				if(player!= this && !player.getFolded())
				{
					if(player.getLastAction() != null)
					{
						double handStrength = opponentModeler.getOpponentContextStatistics(
								i, 								//hvilken spiller �nsker man � finne statistikk om?
								gameRound.getState(), 
								PlayersLeft.get(gameRound.getPlayersLeft()),
								TablePosition.get(gameRound.getPositionRelativeToDealer(this)), 
								ActionEnum.get(player.getLastAction().getActionType())); 		
				
						if(handStrength > bestPredictedHandStrength)
							bestPredictedHandStrength = handStrength;
					}
				}			
			}
		}
		
		ArrayList<ActionType> legalActions = Rules.getLegalActions(this);
		Printer.printAvailbleActions(this, legalActions);
		Printer.printValueToCall(this, gameRound.getCurrentBet() - getPostedCash());
		int playersLeft = gameRound.getPlayersLeft();
		
		PlayersLeft pLeft = PlayersLeft.get(playersLeft);
		int position = gameRound.getPosition(this) - gameRound.getDealerPosition() % gameRound.getPlayers().size();
		TablePosition tPosition = TablePosition.get(position);
		
		double handStrength;
		if(gameRound.getIsPreFlop())
			handStrength = HandStrength.getHandStrengthPreFlop(getPocketCards(), playersLeft);
		else
			handStrength = HandStrength.calculateHandStrength(getPocketCards(), gameRound.getCommunityCards(), playersLeft);
		
		double potOdds = getPotOdds(gameRound);

		double otherFactors = 0;

		if(bestPredictedHandStrength < handStrength)
		{
			otherFactors = 0.05;
		}
		else
		{
			if(!conservative)
				otherFactors = 0.1;
		}
		
		switch (tPosition) 
		{
			case early:
				if(handStrength > potOdds)
					otherFactors += .01;
			break;
			case med:
				if(handStrength > potOdds)
					otherFactors += .02;
				else
					otherFactors += .01;
			break;
			case late:
				if(handStrength > potOdds)
					otherFactors += .04;
				else
					otherFactors += .02;
			break;
		}
		
		ActionType actionType = ActionType.FOLD;
		
		switch(pLeft)
		{
		case few:
			//A raise hand
			//Note: små endringer har veldig sort utslag
			if(handStrength + otherFactors > 0.47)
			{
				if(legalActions.contains(ActionType.RAISE) || legalActions.contains(ActionType.BET))
					actionType = ActionType.RAISE;
				else
					actionType = ActionType.CALL;
			}
			//A call hand
			else if(handStrength + otherFactors > 0.25)
			{
				if(legalActions.contains(ActionType.CHECK))
					actionType = ActionType.CHECK;
				else
					actionType = ActionType.CALL;
			}
			//A fold hand
			else
			{
				if(legalActions.contains(ActionType.CHECK))
					actionType = ActionType.CHECK;
				else
					actionType = ActionType.FOLD;
			}
			
			break;
		case some:
			//A raise hand
			if(handStrength + otherFactors > 0.22)
			{
				if(legalActions.contains(ActionType.RAISE) || legalActions.contains(ActionType.BET))
					actionType = ActionType.RAISE;
				else
					actionType = ActionType.CALL;
			}
			//A call hand
			else if(handStrength + otherFactors > 0.19)
			{
				if(legalActions.contains(ActionType.CHECK))
					actionType = ActionType.CHECK;
				else
					actionType = ActionType.CALL;
			}
			//A fold hand
			else
			{
				if(legalActions.contains(ActionType.CHECK))
					actionType = ActionType.CHECK;
				else
					actionType = ActionType.FOLD;
			}
			break;
		case many:
			//A raise hand
			if(handStrength + otherFactors > 0.14)
			{
				if(legalActions.contains(ActionType.RAISE) || legalActions.contains(ActionType.BET)) 
					actionType = ActionType.RAISE;
				else
					actionType = ActionType.CALL;
			}
			//A call hand
			else if(handStrength + otherFactors > 0.11)
			{
				if(legalActions.contains(ActionType.CHECK))
					actionType = ActionType.CHECK;
				else
					actionType = ActionType.CALL;
			}
			//A fold hand
			else
			{
				if(legalActions.contains(ActionType.CHECK))
					actionType = ActionType.CHECK;
				else 
					actionType = ActionType.FOLD;
			}
			break;
		}
		return actionType;
	}
}
